#include "Keyboard.h"
#include <GL/glut.h>
#include "Game.h"
#include "Food.h"
#include "Portal.h"
#include "Scroll.h"
#include "Equipment.h"
#include "ItemStack.h"
#include "GameObject.h"
#include "Tile.h"
#include "Recipe.h"
#include "GameState.h"
#include "Player.h"
#include "StringLib.h"
#include "ItemContainer.h"
#include "Util.h"
#include "RecipeManager.h"
#include "Trap.h"
#include "Level.h"
#include "AvailableTalents.h"
#include "RangedWeapon.h"
#include <cstring>
#ifdef _WIN32
#include "lib/dirent.h"
#else
#include <dirent.h>
#endif

void Keyboard::handleInput(unsigned char key, int x, int y) {
	g_keyboard->handleInput(key);
}

void Keyboard::handleSpecInput(int key, int x, int y) {
	g_keyboard->handleSpecInput(key);
}

Keyboard::Keyboard() {
	m_counter = 0;
	m_selectedItemStack = NULL;
	m_selectedObject = NULL;
	m_selectedTile = NULL;
	m_selectedRecipe = NULL;
	m_selectedScroll = NULL;
	m_availableTalents = NULL;
}

Keyboard::~Keyboard() {
}

void Keyboard::resetKeyboard() {
	m_counter = 0;
	deleteItemStack();
	m_loadGames.clear();
	m_selectedObject = NULL;
	m_selectedTile = NULL;
	m_selectedRecipe = NULL;
	m_selectedScroll = NULL;
	if(m_availableTalents)
		delete m_availableTalents;
	m_availableTalents = NULL;
}

void Keyboard::handleInput(unsigned char key) {
	switch(g_gameMode.top()) {
	case GM_TITLE:
		switch(key) {
		case 'n':
			newGame();
			break;
		case 'l': {
			DIR *dir = opendir("saves");
			struct dirent *ent;
			m_loadGames.clear();
			if (dir != NULL) {
				while ((ent = readdir(dir)) != NULL) {
					if(strcmp(".", ent->d_name) && strcmp("..", ent->d_name)) {
						m_loadGames.push_back(std::string(ent->d_name));
					}
				}
				closedir(dir);
			} else {
				exit(-1);
			}
			g_gameMode.push(GM_LOAD);
			break;
		}
		case 'q':
			exit(1);
			break;
		}
		glutPostRedisplay();
		return;
	case GM_LOAD:
		if(key == 27) {
			g_gameMode.pop();
		} else {
			int mod = Util::letterMod(key);
			if(mod >= 0 && mod < int(m_loadGames.size())) {
				loadGame(m_loadGames[mod]);
			}
		}
		glutPostRedisplay();
		return;
	}
	if(!g_gameState->isPlayersTurn()) return;
	switch(g_gameMode.top()) {
	case GM_DEAD: {
		switch(key) {
		case 'l':
			g_gameMode.push(GM_SHOW_TEXT_LOG);
			break;
		case 'i':
			m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_INVENTORY), g_options.o_height);
			g_gameMode.push(GM_SHOW_ITEM_STACK);
			break;
		case 'x':
			m_selectedTile = g_player->getTile();
			g_gameMode.push(GM_EXAMINE_LEVEL);
			break;
		case 27:
			clearGame();
			break;
		}
		break;
	}
	case GM_FOLLOW_PLAYER: {
		switch(key) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			if(glutGetModifiers() & GLUT_ACTIVE_CTRL) {
				if(key != '5')
					g_player->doMeleeAttack(g_currentLevel->getTile((key-'1')%3-1,(key-'1')/3-1)->getCharacter());
			} else {
				g_player->move((key-'1')%3-1,(key-'1')/3-1);
			}
			break;
		case 'Q':
			clearGame();
			deleteOldGame();
			break;
		case 'l':
			g_gameMode.push(GM_SHOW_TEXT_LOG);
			break;
		case ',':
			handlePickUp();
			break;
		case 'i':
			m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_INVENTORY), g_options.o_height);
			g_gameMode.push(GM_SHOW_ITEM_STACK);
			break;
		case 'x':
			m_selectedTile = g_player->getTile();
			g_gameMode.push(GM_EXAMINE_LEVEL);
			break;
		case 'd':
			m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_DROP), g_options.o_height);
			g_gameMode.push(GM_DROP_ITEMS);
			break;
		case 'w':
			g_gameMode.push(GM_SHOW_EQUIPMENT);
			break;
		case 'u':
			g_gameMode.push(GM_LOCK_UNLOCK);
			g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_LOCK_UNLOCK));
			break;
		case 'v':
			if(g_player->getTile()->getObstacle() != NULL && g_player->getTile()->getObstacle()->getType(TH_GENERIC_TYPE) == GT_OB_ITEMCONTAINER
					&& g_player->getTile()->getObstacle()->getType(TH_ITEMCONTAINER_TYPE) != ICT_POTTERY) {
				if(((ItemContainer*)g_player->getTile()->getObstacle())->isLocked()) {
					g_player->unlockLock(((ItemContainer*)g_player->getTile()->getObstacle()), 0);
				}
				if(!((ItemContainer*)g_player->getTile()->getObstacle())->isLocked()) {
					m_selectedItemStack = new ItemStack(((ItemContainer*)g_player->getTile()->getObstacle())->getItems(), g_stringLib->getTextString(ST_INPUT_LOOT_CHEST), g_options.o_height);
					g_gameMode.push(GM_LOOT_CHEST);
				}
			}
			break;
		case 'q':
			m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_QUAFF),  g_options.o_height);
			m_selectedItemStack->setFilter(FT_POTION);
			g_gameMode.push(GM_SELECT_QUAFF_ITEM);
			break;
		case 'k':
			g_gameMode.push(GM_KICK);
			g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_KICK));
			break;
		case 'c':
			g_gameMode.push(GM_SELECT_RECIPE);
			break;
		case 'e':
			m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_EAT), g_options.o_height);
			m_selectedItemStack->setFilter(FT_FOOD);
			g_gameMode.push(GM_SELECT_FOOD);
			break;
		case '>':
		case '<':
			handlePortal(key == '<');
			break;
		case 'r':
			m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_SCROLL), g_options.o_height);
			m_selectedItemStack->setFilter(FT_SCROLL);
			g_gameMode.push(GM_SELECT_SCROLL);
			break;
		case 'f': {
			Item* leftHand = g_player->getEquipment()->get(EL_LEFT_HAND);
			Item* rightHand = g_player->getEquipment()->get(EL_RIGHT_HAND);
			bool firing = false;
			if(leftHand != NULL && leftHand->getType(TH_GENERIC_TYPE) == GT_IT_RANGED_WEAPON) {
				if(((RangedWeapon*)leftHand)->getCurrentAmmo() > 0) {
					g_gameMode.push(GM_RANGED_TARGET);
					m_selectedTile = g_player->getTile(); // eventually, target nearest enemy by default
					firing = true;
				} else
					g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_NO_AMMO));
			}
			if(!firing && rightHand != NULL && rightHand->getType(TH_GENERIC_TYPE) == GT_IT_RANGED_WEAPON) {
				if(((RangedWeapon*)rightHand)->getCurrentAmmo() > 0) {
					g_gameMode.push(GM_RANGED_TARGET);
					m_selectedTile = g_player->getTile(); // eventually, target nearest enemy by default
					firing = true;
				} else
					g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_NO_AMMO));
			}
			if(!firing)
				g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_NO_RANGED));
			break;
		}
		case 'R':
			g_player->reload();
			break;
		case 'S':
			saveGame();
			exit(1);
		}
		break;
	}
	case GM_SHOW_TEXT_LOG: {
		switch(key) {
		case 27:
			g_textLog->resetCurrentLine();
			g_gameMode.pop();
			break;
		}
		break;
	}
	case GM_PICK_UP: {
		switch(key) {
		case 'y':
		case 'n':
		case 'q':
		case 'a':
		case ',':
		case '?':
		case '*':
		case 27:
			handlePickUp(key);
		}
		break;
	}
	case GM_SHOW_ITEM_STACK: {
		if(key == 27) {
			deleteItemStack();
			g_gameMode.pop();
		} else if((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) {
			int mod = Util::letterMod(key);
			Item* item = m_selectedItemStack->getItem(mod);
			if(item) {
				g_gameMode.push(GM_SHOW_OBJECT);
				m_selectedObject = item;
			}
		} else {
			handleFilter(key);
		}
		break;
	}
	case GM_SELECT_SCROLL_ITEM: {
		bool cleanUp = false;
		if(key == 27) {
			cleanUp = true;
		} else if((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) {
			int mod = Util::letterMod(key);
			Item* item = m_selectedItemStack->getItem(mod);
			if(item != NULL) {
				g_player->readScroll(m_selectedScroll, item);
			}
			cleanUp = true;
		}
		if(cleanUp) {
			g_gameMode.pop();
			g_gameMode.pop();
			deleteItemStack();
			m_selectedScroll = NULL;
		}
		break;
	}
	case GM_SELECT_QUAFF_ITEM:
	case GM_SELECT_RECIPE:
	case GM_SELECT_EQUIPMENT_ITEM:
	case GM_SELECT_SCROLL:
	case GM_SELECT_FOOD: {
		if(key == 27) {
			deleteItemStack();
			g_gameMode.pop();
		} else if((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) {
			int mod = Util::letterMod(key);
			switch(g_gameMode.top()) {
			case GM_SELECT_QUAFF_ITEM: {
				Item* item = m_selectedItemStack->getItem(mod);
				if(item != NULL && item->getType(TH_GENERIC_TYPE) == GT_IT_POTION) {
					g_player->quaff((Potion*)item);
					deleteItemStack();
					g_gameMode.pop();
				}
				break;
			}
			case GM_SELECT_RECIPE: {
				Recipe* recipe = g_recipeManager->getRecipe(mod);
				if(recipe != NULL) {
					m_selectedRecipe = recipe;
					g_gameMode.push(GM_VIEW_RECIPE);
				}
				break;
			}
			case GM_SELECT_EQUIPMENT_ITEM: {
				Item* item = m_selectedItemStack->getItem(mod);
				if(item != NULL && g_player->getEquipment()->get(m_selectedEquipmentLocation) != item) {
					bool equipped = g_player->equip(m_selectedEquipmentLocation, item);
					deleteItemStack();
					g_gameMode.pop();
					if(!equipped)
						g_gameMode.pop();
				}
				break;
			}
			case GM_SELECT_FOOD: {
				Item* item = m_selectedItemStack->getItem(mod);
				if(item != NULL && item->getType(TH_GENERIC_TYPE) == GT_IT_FOOD) {
					g_player->eat((Food*)item);
					deleteItemStack();
					g_gameMode.pop();
				}
				break;
			}
			case GM_SELECT_SCROLL: {
				Item* item = m_selectedItemStack->getItem(mod);
				if(item != NULL && item->getType(TH_GENERIC_TYPE) == GT_IT_SCROLL) {
					handleScroll((Scroll*)item);
				}
				break;
			}
			}
			
		}
		break;
	}
	case GM_EXAMINE_LEVEL: {
		switch(key) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '6':
		case '7':
		case '8':
		case '9': {
			int modX = (key-'1')%3-1;
			int modY = (key-'1')/3-1;
			if(m_selectedTile->getX()+modX >= 0 && m_selectedTile->getX()+modX < COLS && m_selectedTile->getY()+modY >= 0 && m_selectedTile->getY()+modY < ROWS) {
				m_selectedTile = g_currentLevel->getTile(m_selectedTile->getX()+modX, m_selectedTile->getY()+modY);
				if(m_selectedTile->isExplored())
					m_selectedTile->logDetails(*g_textLog);
			}
			break;
		}
		case 'v':
			if(m_selectedTile->isExplored()) {
				if(m_selectedTile->getCharacter()) {
					m_selectedObject = m_selectedTile->getCharacter();
					g_gameMode.push(GM_SHOW_OBJECT);
					break;
				} else if(m_selectedTile->getObstacle()) {
					Obstacle* obstacle = m_selectedTile->getObstacle();
					if(obstacle->getType(TH_GENERIC_TYPE) == GT_OB_TRAP) {
						if(((Trap*)obstacle)->isVisible()) {
							m_selectedObject = obstacle;
							g_gameMode.push(GM_SHOW_OBJECT);
							break;
						}
					} else {
						m_selectedObject = obstacle;
						g_gameMode.push(GM_SHOW_OBJECT);
						break;
					}
				}
				if(m_selectedTile->getNumItems() > 1) {
					m_selectedItemStack = new ItemStack(m_selectedTile->getItems(), g_stringLib->getTextString(ST_INPUT_VIEW_ITEM_STACK), g_options.o_height);
					g_gameMode.push(GM_SHOW_ITEM_STACK);
					break;
				} else if(m_selectedTile->getNumItems() == 1) {
					m_selectedObject = m_selectedTile->getItem(0);
					g_gameMode.push(GM_SHOW_OBJECT);
					break;
				}
			}
			break;
		case 27:
			m_selectedTile = NULL;
			g_gameMode.pop();
			break;
		}
		break;
	}
	case GM_RANGED_TARGET: {
		switch(key) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '6':
		case '7':
		case '8':
		case '9': {
			int modX = (key-'1')%3-1;
			int modY = (key-'1')/3-1;
			if(m_selectedTile->getX()+modX >= 0 && m_selectedTile->getX()+modX < COLS && m_selectedTile->getY()+modY >= 0 && m_selectedTile->getY()+modY < ROWS) {
				m_selectedTile = g_currentLevel->getTile(m_selectedTile->getX()+modX, m_selectedTile->getY()+modY);
			}
			break;
		}
		case 'f':
			//g_player->fire(m_selectedTile->getX(), m_selectedTile->getY());
			break;
		case 27:
			m_selectedTile = NULL;
			g_gameMode.pop();
			break;
		}
		break;
	}
	case GM_DROP_ITEMS:
	case GM_PICK_UP_MULTI:
	case GM_LOOT_CHEST: {
		if(key == 27) {
			deleteItemStack();
			g_gameMode.pop();
		} else if(key == 13) {
			if(g_gameMode.top() == GM_DROP_ITEMS) {
				std::vector<Item*>* items = m_selectedItemStack->getSelectedItems();
				for(std::vector<Item*>::iterator iter = items->begin(); iter != items->end(); iter++) {
					g_player->drop(*iter);
				}
				delete items;
			} else if(g_gameMode.top() == GM_PICK_UP_MULTI) {
				std::vector<Item*>* items = m_selectedItemStack->getSelectedItems();
				for(unsigned int i = 0; i < items->size(); i++)
					g_player->pickUp(items->at(i));
				delete items;
			} else if(g_gameMode.top() == GM_LOOT_CHEST) {
				ItemContainer* container = (ItemContainer*)g_player->getTile()->getObstacle();
				std::vector<Item*>* items = m_selectedItemStack->getSelectedItems();
				for(unsigned int i = 0; i < items->size(); i++)
					g_player->pickUp(items->at(i));
				delete items;
			}
			deleteItemStack();
			g_gameMode.pop();
		} else if((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) {
			int mod = Util::letterMod(key);
			m_selectedItemStack->selectItem(mod);
		}
		break;
	}
	case GM_SHOW_OBJECT: {
		if(key == 27) {
			m_selectedObject = NULL;
			g_gameMode.pop();
		}
		break;
	}
	case GM_SHOW_EQUIPMENT: {
		if(key == 27) {
			g_gameMode.pop();
		} else if(key >= 'a' && key < ('a'+NUM_EQUIPMENT_LOCATIONS)) {
			EquipmentLocation location = EquipmentLocation(key-'a');
			if(g_player->getEquipment()->isEquipped(location)) {
				if(!g_player->unequip(location))
					g_gameMode.pop();
			} else {
				m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_EQUIP, g_stringLib->getMiscString(MST_EQUIPMENT, location).c_str()), g_options.o_height);
				switch(location) {
				case EL_LEFT_HAND:
				case EL_RIGHT_HAND:
					m_selectedItemStack->showOnly(TH_GENERIC_TYPE, GT_IT_MELEE_WEAPON);
					m_selectedItemStack->show(TH_GENERIC_TYPE, GT_IT_RANGED_WEAPON);
					m_selectedItemStack->show(TH_GENERIC_TYPE, GT_IT_SHIELD);
					m_selectedItemStack->show(TH_GENERIC_TYPE, GT_IT_TOOL);
					if(location == EL_LEFT_HAND && g_player->getEquipment()->get(EL_RIGHT_HAND) != NULL)
						m_selectedItemStack->setVisible(g_player->getEquipment()->get(EL_RIGHT_HAND), false);
					else if(location == EL_RIGHT_HAND && g_player->getEquipment()->get(EL_LEFT_HAND) != NULL)
						m_selectedItemStack->setVisible(g_player->getEquipment()->get(EL_LEFT_HAND), false);
					break;
				case EL_HEAD:
					m_selectedItemStack->showOnly(TH_ARMOR_FAMILY, AF_HEAD);
					break;
				case EL_BODY:
					m_selectedItemStack->showOnly(TH_ARMOR_FAMILY, AF_BODY);
					break;
				case EL_HANDS:
					m_selectedItemStack->showOnly(TH_ARMOR_FAMILY, AF_HANDS);
					break;
				case EL_LEGS:
					m_selectedItemStack->showOnly(TH_ARMOR_FAMILY, AF_LEGS);
					break;
				case EL_FEET:
					m_selectedItemStack->showOnly(TH_ARMOR_FAMILY, AF_FEET);
					break;
				}
				m_selectedEquipmentLocation = location;
				g_gameMode.push(GM_SELECT_EQUIPMENT_ITEM);
			}
		}
		break;
	}
	case GM_LOCK_UNLOCK:
	case GM_KICK: {
		if(key == 27) {
			g_gameMode.pop();
		} else if(key >= '1' && key <= '9') {
			if(g_gameMode.top() == GM_LOCK_UNLOCK)
				lockUnlock((key-'1')%3-1, (key-'1')/3-1);
			else if(g_gameMode.top() == GM_KICK) {
				g_player->doKick((key-'1')%3-1, (key-'1')/3-1);
				g_gameMode.pop();
			}
		}
		break;
	}
	case GM_VIEW_RECIPE: {
		if(key == 27) {
			deleteItemStack();
			g_gameMode.pop();
		} else if(key == 'c') {
			if(m_selectedRecipe->canCraft(g_player)) {
				m_selectedItemStack = new ItemStack(g_player->getInventory(), g_stringLib->getTextString(ST_INPUT_INGREDIENT, m_selectedRecipe->getCurrentItem()->name.c_str()), g_options.o_height);
				m_selectedItemStack->showOnly(m_selectedRecipe->getCurrentItem()->typeCategory, m_selectedRecipe->getCurrentItem()->type);
				g_gameMode.push(GM_SELECT_RECIPE_ITEMS);
			}
		}
		break;
	}
	case GM_SELECT_RECIPE_ITEMS: {
		bool craft = false;
		if(key == 27) {
			m_selectedRecipe->clearSelectedItems();
			deleteItemStack();
			g_gameMode.pop();
		} else if((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) {
			int mod = Util::letterMod(key);
			Item* item = m_selectedItemStack->getItem(mod);
			if(item) {
				int currentItem = m_selectedRecipe->getCurrentItemAsInt();
				m_selectedRecipe->selectItem(item);
				m_selectedItemStack->stackChange(item, 1);
				if(m_selectedRecipe->readyForCraft()) {
					craft = true;
				} else {
					if(currentItem == m_selectedRecipe->getCurrentItemAsInt()) {
						m_selectedItemStack->showOnly(ItemStack::typeHierarchyMap[GenericType(item->getType(TH_GENERIC_TYPE))], item->getType(ItemStack::typeHierarchyMap[GenericType(item->getType(TH_GENERIC_TYPE))]));
					} else {
						m_selectedItemStack->showOnly(m_selectedRecipe->getCurrentItem()->typeCategory, m_selectedRecipe->getCurrentItem()->type);
					}
					m_selectedItemStack->setTitle(g_stringLib->getTextString(ST_INPUT_INGREDIENT, m_selectedRecipe->getCurrentItem()->name.c_str()));
				}
			}
		} else if(key == 13 && !m_selectedRecipe->getCurrentItem()->required) {
			m_selectedRecipe->skipItem();
			if(m_selectedRecipe->readyForCraft()) {
				craft = true;
			} else {
				m_selectedItemStack->setTitle(g_stringLib->getTextString(ST_INPUT_INGREDIENT, m_selectedRecipe->getCurrentItem()->name.c_str()));
				m_selectedItemStack->showOnly(m_selectedRecipe->getCurrentItem()->typeCategory, m_selectedRecipe->getCurrentItem()->type);
			}
		}
		if(craft) {
			m_selectedRecipe->craft(g_player);
			m_selectedRecipe = NULL;
			g_gameMode.pop();
			g_gameMode.pop();
			g_gameMode.pop();
			deleteItemStack();
		}
		break;
		}
	case GM_SELECT_TALENT: {
		bool destroy = false;
		if(m_availableTalents->getTalents()->size() == 0)
			destroy = true;
		else {
			int mod = Util::letterMod(key);
			int talent = m_availableTalents->getTalent(mod);
			if(talent != -1) {
				g_player->addTalent(Talent(talent));
				destroy = true;
			}
		}
		if(destroy) {
			delete m_availableTalents;
			m_availableTalents = NULL;
			g_gameMode.pop();
		}
		break;
	}
	case GM_SELECT_SKILL: {
		int mod = Util::letterMod(key);
		int counter = 0;
		for(int i = 0; i < NUM_SKILLS; i++) {
			Skill skill = Skill(i);
			if(g_player->hasSkill(skill) && g_player->getSkillLevel(skill) < 10) {
				if(counter == mod) {
					g_player->trainSkill(skill, float((rand(10))+1)*0.1f);
					counter++;
					g_gameMode.pop();
					break;
				}
				counter++;
			}
		}
		if(counter == 0) {
			while(g_gameMode.top() == GM_SELECT_SKILL)
				g_gameMode.pop();
		}
		break;
	}
	case GM_SELECT_NEW_SKILL: {
		int mod = Util::letterMod(key);
		int counter = 0;
		for(int i = 0; i < NUM_SKILLS; i++) {
			Skill skill = Skill(i);
			if(!g_player->hasSkill(skill)) {
				if(counter == mod) {
					g_player->trainSkill(skill, 1.0f);
					counter++;
					g_gameMode.pop();
					break;
				}
				counter++;
			}
		}
		if(counter == 0)
			g_gameMode.pop();
		break;
	}
	}
	if(g_gameMode.top() != GM_SELECT_TALENT && g_gameMode.top() != GM_TITLE)
		g_gameState->checkPlayerTookTurn();
	glutPostRedisplay();
}

void Keyboard::handleSpecInput(int key) {
	switch(g_gameMode.top()) {
	case GM_TITLE:
	case GM_LOAD:
		return;
	case GM_FOLLOW_PLAYER: {
		switch(key) {
		case GLUT_KEY_LEFT:
			g_player->move(-1,0);
			break;
		case GLUT_KEY_RIGHT:
			g_player->move(1,0);
			break;
		case GLUT_KEY_UP:
			g_player->move(0,1);
			break;
		case GLUT_KEY_DOWN:
			g_player->move(0,-1);
			break;
		}
		break;
	}
	case GM_SHOW_TEXT_LOG: {
		switch(key) {
		case GLUT_KEY_PAGE_UP:
			g_textLog->page(true);
			break;
		case GLUT_KEY_PAGE_DOWN:
			g_textLog->page(false);
			break;
		case GLUT_KEY_UP:
			g_textLog->shift(true);
			break;
		case GLUT_KEY_DOWN:
			g_textLog->shift(false);
			break;
		}
		break;
	}
	case GM_DROP_ITEMS:
	case GM_PICK_UP_MULTI:
	case GM_SELECT_SCROLL:
	case GM_SELECT_QUAFF_ITEM:
	case GM_SELECT_RECIPE_ITEMS:
	case GM_SHOW_ITEM_STACK: {
		switch(key) {
		case GLUT_KEY_PAGE_UP:
			m_selectedItemStack->page(true);
			break;
		case GLUT_KEY_PAGE_DOWN:
			m_selectedItemStack->page(false);
			break;
		case GLUT_KEY_UP:
			m_selectedItemStack->shift(true);
			break;
		case GLUT_KEY_DOWN:
			m_selectedItemStack->shift(false);
			break;
		}
		break;
	}
	case GM_EXAMINE_LEVEL: {
		int modX = 0;
		int modY = 0;
		switch(key) {
		case GLUT_KEY_LEFT:
			modX = -1;
			break;
		case GLUT_KEY_RIGHT:
			modX = 1;
			break;
		case GLUT_KEY_UP:
			modY = 1;
			break;
		case GLUT_KEY_DOWN:
			modY = -1;
			break;
		}
		if(m_selectedTile->getX()+modX >= 0 && m_selectedTile->getX()+modX < COLS && m_selectedTile->getY()+modY >= 0 && m_selectedTile->getY()+modY < ROWS)
			m_selectedTile = g_currentLevel->getTile(m_selectedTile->getX()+modX, m_selectedTile->getY()+modY);
		break;
	}
	case GM_LOCK_UNLOCK: {
		switch(key) {
		case GLUT_KEY_LEFT:
			lockUnlock(-1, 0);
			break;
		case GLUT_KEY_RIGHT:
			lockUnlock(1, 0);
			break;
		case GLUT_KEY_UP:
			lockUnlock(0, 1);
			break;
		case GLUT_KEY_DOWN:
			lockUnlock(0, -1);
			break;
		}
		break;
	}
	case GM_KICK: {
		switch(key) {
		case GLUT_KEY_LEFT:
			g_player->doKick(-1, 0);
			break;
		case GLUT_KEY_RIGHT:
			g_player->doKick(1, 0);
			break;
		case GLUT_KEY_UP:
			g_player->doKick(0, 1);
			break;
		case GLUT_KEY_DOWN:
			g_player->doKick(0, -1);
			break;
		}
		break;
	}
	}
	if(g_gameMode.top() != GM_SELECT_TALENT && g_gameMode.top() != GM_TITLE)
		g_gameState->checkPlayerTookTurn();
	glutPostRedisplay();
}

void Keyboard::handlePickUp(char c) {
	if(!g_gameState->isPlayersTurn()) return;
	if(g_gameMode.top() == GM_FOLLOW_PLAYER) {
		if(g_player->getTile()->getNumItems() == 0) return;
		if(g_player->getTile()->getNumItems() == 1) {
			Item* item = g_player->getTile()->getItem(0);
			if(g_player->pickUp(item))
				return;
		} else {
			g_gameMode.push(GM_PICK_UP);
		}
	}
	bool reset = false, viewAll = false;
	if(g_gameMode.top() == GM_PICK_UP) {
		Item* item = g_player->getTile()->getItem(m_counter);
		if(c != 0) {
			switch(c) {
			case 'a':
				for(int i = m_counter; true;) {
					if(!g_player->pickUp(item))
						break;
					if(i == g_player->getTile()->getNumItems()) break;
					item = g_player->getTile()->getItem(m_counter);
				}
				reset = true;
				break;
			case 'y':
				if(g_player->pickUp(item)) {
					if(g_player->getTile()->getNumItems() == m_counter) {
						reset = true;
						break;
					}
				} else {
					reset = true;
				}
				break;
			case 'n':
				m_counter++;
				if(g_player->getTile()->getNumItems() == m_counter) {
					reset = true;
				}
				break;
			case 27:
			case 'q':
				reset = true;
				g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_CANCEL));
				break;
			case '*':
			case ',':
				reset = true;
				viewAll = true;
				break;
			case '?':
				g_textLog->addLine(item->getDescription());
				break;
			}
		}
		if(!reset) {
			item = g_player->getTile()->getItem(m_counter);
			g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_PICK_UP_ASK, item->getColoredName().c_str()));
		}
	}
	if(reset) {
		m_counter = 0;
		g_gameMode.pop();
	}
	if(viewAll) {
		m_selectedItemStack = new ItemStack(g_player->getTile()->getItems(), g_stringLib->getTextString(ST_INPUT_PICK_UP_MULTIPLE), g_options.o_height);
		g_gameMode.push(GM_PICK_UP_MULTI);
	}
}

void Keyboard::lockUnlock(int x, int y) {
	int newX = int(g_player->getTile()->getX())+x;
	int newY = int(g_player->getTile()->getY())+y;
	Obstacle* obstacle = g_currentLevel->getTile(newX, newY)->getObstacle();
	if(obstacle != NULL && (obstacle->getType(TH_GENERIC_TYPE) == GT_OB_DOOR || obstacle->getType(TH_GENERIC_TYPE) == GT_OB_ITEMCONTAINER) && ((LockedObstacle*)obstacle)->getLockType() != LT_NONE) {
		g_player->unlockLock((LockedObstacle*)obstacle, 1);
		g_gameMode.pop();
	} else {
		g_textLog->addLine(g_stringLib->getTextString(ST_INPUT_NO_LOCK));
		g_gameMode.pop();
		return;
	}
}

void Keyboard::handleFilter(char key) {
	switch(key) {
	case '/':
		m_selectedItemStack->getFilter() == FT_MELEE_WEAPON ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_MELEE_WEAPON);
		break;
	case '\'':
		m_selectedItemStack->getFilter() == FT_MISC ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_MISC);
		break;
	case '!':
		m_selectedItemStack->getFilter() == FT_POTION ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_POTION);
		break;
	case '\\':
		m_selectedItemStack->getFilter() == FT_TOOL ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_TOOL);
		break;
	case '+':
		m_selectedItemStack->getFilter() == FT_INGREDIENT ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_INGREDIENT);
		break;
	case '%':
		m_selectedItemStack->getFilter() == FT_FOOD ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_FOOD);
		break;
	case '?':
		m_selectedItemStack->getFilter() == FT_SCROLL ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_SCROLL);
		break;
	case '[':
		m_selectedItemStack->getFilter() == FT_ARMOR ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_ARMOR);
		break;
	case ']':
		m_selectedItemStack->getFilter() == FT_SHIELD ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_SHIELD);
		break;
	case '.':
		m_selectedItemStack->getFilter() == FT_AMMO ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_AMMO);
		break;
	case '}':
		m_selectedItemStack->getFilter() == FT_RANGED_WEAPON ? m_selectedItemStack->setFilter(-1) : m_selectedItemStack->setFilter(FT_RANGED_WEAPON);
		break;
	}
}

void Keyboard::deleteItemStack() {
	if(m_selectedItemStack != NULL) {
		delete m_selectedItemStack;
		m_selectedItemStack = NULL;
	}
}

void Keyboard::handlePortal(bool up) {
	if(g_player->getTile()->getObstacle() != NULL && g_player->getTile()->getObstacle()->getType(TH_GENERIC_TYPE) == GT_OB_PORTAL) {
		Portal* portal = (Portal*)(g_player->getTile()->getObstacle());
		if(up == portal->isUp())
			portal->takePortal(g_player);
	}
}

void Keyboard::handleScroll(Scroll* scroll) {
	m_selectedItemStack->setFilter(-1);
	m_selectedScroll = scroll;
	ScrollType type = (ScrollType)scroll->getType(TH_SCROLL_TYPE);
	if(type == ST_IDENTIFY && scroll->getStatus() != BLESSED) {
		std::list<Item*>* inventory = g_player->getInventory();
		m_selectedItemStack->setVisible(scroll, false);
		for(std::list<Item*>::iterator iter = inventory->begin(); iter != inventory->end(); iter++) {
			if((*iter)->isStatusIdentified() && (*iter)->isIdentified())
				m_selectedItemStack->setVisible(*iter, false);
		}
		g_gameMode.push(GM_SELECT_SCROLL_ITEM);
		m_selectedItemStack->setTitle(g_stringLib->getTextString(ST_INPUT_SCROLL_ITEM, std::string("identify").c_str()));
	} else if(type == ST_UNCURSE && scroll->getStatus() != BLESSED) {
		std::list<Item*>* inventory = g_player->getInventory();
		m_selectedItemStack->setVisible(scroll, false);
		for(std::list<Item*>::iterator iter = inventory->begin(); iter != inventory->end(); iter++) {
			if((*iter)->getStatus() != CURSED && ((*iter)->isStatusIdentified()))
				m_selectedItemStack->setVisible(*iter, false);
		}
		g_gameMode.push(GM_SELECT_SCROLL_ITEM);
		m_selectedItemStack->setTitle(g_stringLib->getTextString(ST_INPUT_SCROLL_ITEM, std::string("uncurse").c_str()));
	} else {
		g_player->readScroll(scroll);
		g_gameMode.pop();
		deleteItemStack();
		m_selectedScroll = NULL;
	}
}

void Keyboard::initTalentList(Player* player) {
	if(m_availableTalents == NULL)
		m_availableTalents = new AvailableTalents(player);
}
